# encoding=utf-8
# Example of embedding CEF Python browser using wxPython library.
# This example has a top menu and a browser widget without navigation bar.

# To install wxPython on Linux type "sudo apt-get install python-wxtools".

# Tested configurations:
# - wxPython 3.0 on Windows/Mac
# - wxPython 2.8 on Linux
# - CEF Python v55.4+

import logging
import os
import platform
import sys

import wx
import wx.aui
from cefpython3 import cefpython as cef

g_strVersion = "ver0.0.1.0 - 2017-11-9"
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s\t\t%(funcName)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename=r'G:\_TMP\wxpython.log',
                    filemode='w')
# 定义一个StreamHandler，将INFO级别或更高的日志信息打印到标准错误，并将其添加到当前的日志处理对象#
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter = logging.Formatter(
    '%(name)-8s: %(levelname)-8s [%(process)-5d-%(thread)-5d]%(threadName)-12s\t%(message)s\t\t%(funcName)s:%(lineno)d')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)

logging.info(g_strVersion)

# Fix for PyCharm hints warnings when using static methods
WindowUtils = cef.WindowUtils()

# Platforms
WINDOWS = (platform.system() == "Windows")
LINUX = (platform.system() == "Linux")
MAC = (platform.system() == "Darwin")

# Configuration
WIDTH = 1024
HEIGHT = 576

# Globals
g_count_windows = 0


class MyPanel_Script(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 80),
                          style=wx.TAB_TRAVERSAL)

        hboxScript = wx.BoxSizer(wx.HORIZONTAL)

        strScript = '''window.location="https://passport.jd.com/new/login.aspx"'''
        self.m_textScript = wx.TextCtrl(self, wx.ID_ANY, strScript, wx.DefaultPosition, wx.Size(-1, -1),
                                        wx.TE_MULTILINE)
        hboxScript.Add(self.m_textScript, 1, wx.EXPAND, 15)

        self.m_btnScript = wx.Button(self, wx.ID_ANY, u"执行脚本", wx.Point(-1, -1), wx.Size(-1, -1), 0)
        self.m_btnScript.Bind(wx.EVT_BUTTON, self.OnBtnScript)
        hboxScript.Add(self.m_btnScript, 0, wx.ALL, 5)

        self.m_btnTest = wx.Button(self, wx.ID_ANY+1, u"测试", wx.Point(-1, -1), wx.Size(-1, -1), 0)
        self.m_btnTest.Bind(wx.EVT_BUTTON, self.OnBtnTest)
        hboxScript.Add(self.m_btnTest, 0, wx.ALL, 5)

        self.SetSizer(hboxScript)
        self.Layout()

    def __del__(self):
        pass

    def OnBtnScript(self, event):
        strScript = self.m_textScript.GetValue()
        print("OnBtnScript:" + strScript)
        self.GetParent().ExecuteJavascript(strScript)

    def OnBtnTest(self, event):
        logging.debug(event)
        self.GetParent().browser.SendMouseClickEvent(550, 350, cef.MOUSEBUTTON_LEFT, mouseUp=False, clickCount=1)
        self.GetParent().browser.SendMouseClickEvent(550, 350, cef.MOUSEBUTTON_LEFT, mouseUp=True, clickCount=1)


class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
                          title='my cef3', size=(WIDTH, HEIGHT))
        self.browser = None

        # Must ignore X11 errors like 'BadWindow' and others by
        # installing X11 error handlers. This must be done after
        # wx was intialized.
        if LINUX:
            WindowUtils.InstallX11ErrorHandlers()

        global g_count_windows
        g_count_windows += 1

        self.setup_icon()
        # self.create_menu()
        # self.create_toolbar()
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        # Set wx.WANTS_CHARS style for the keyboard to work.
        # This style also needs to be set for all parent controls.
        self.browser_panel = wx.Panel(self, style=wx.WANTS_CHARS)
        self.browser_panel.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        self.browser_panel.Bind(wx.EVT_SIZE, self.OnSize)

        self.script_panel = MyPanel_Script(self)

        # add the panes to the manager
        self._mgr = wx.aui.AuiManager(self)
        self._mgr.AddPane(window=self.script_panel, info=wx.aui.AuiPaneInfo().Bottom().MaximizeButton(True))
        self._mgr.AddPane(window=self.browser_panel, info=wx.aui.AuiPaneInfo().Center())

        # tell the manager to 'commit' all the changes just made
        self._mgr.Update()

        # On Linux must show before embedding browser, so that handle
        # is available.
        if LINUX:
            self.Show()
            self.embed_browser()
        else:
            self.embed_browser()
            self.Show()

    # 执行脚本
    def ExecuteJavascript(self, strScript):
        self.browser.ExecuteJavascript(strScript)

    def setup_icon(self):
        icon_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                 "resources", "wxpython.png")
        if os.path.exists(icon_file):
            icon = wx.IconFromBitmap(wx.Bitmap(icon_file, wx.BITMAP_TYPE_PNG))
            self.SetIcon(icon)

    def create_menu(self):
        filemenu = wx.Menu()
        filemenu.Append(1, "Some option")
        filemenu.Append(2, "Another option")
        menubar = wx.MenuBar()
        menubar.Append(filemenu, "&File")
        self.SetMenuBar(menubar)

    def create_toolbar(self):
        return
        # 创建工具栏
        toolbar = self.CreateToolBar()
        # 增加一个工具
        toolbar.AddSimpleTool(wx.NewId(), wx.Bitmap("1.png"), "New", "Long help for 'New'")
        toolbar.AddSimpleTool(wx.NewId(), wx.Bitmap("1.png"), "Edit", "Long help for 'Edit'")
        # 准备显示
        toolbar.Realize()

    def embed_browser(self):
        window_info = cef.WindowInfo()
        (width, height) = self.browser_panel.GetClientSizeTuple()
        window_info.SetAsChild(self.browser_panel.GetHandle(),
                               [0, 0, width, height])
        self.browser = cef.CreateBrowserSync(window_info,
                                             #                                     url="http://www.baidu.com/")
                                             url="http://192.168.3.40/p/PowerPointFrame.aspx?embed=1&WOPISrc=http%3A%2F%2F192.168.3.40%3a8081%2fphoenix%2fservice%2fdoc%2fwopi%2ffiles%2F*home*upload*resource_item_global*20171026*a0055507-a54d-4e5d-9114-23caf1135fc4.pptx%2fpptx")
        self.browser.SetClientHandler(MyClientHandler())
        self.browser.SetClientHandler(MyDownloadHandler())
        self.browser.SetClientHandler(MyRequestHandler())
        self.browser.SetClientHandler(MyDialogHandler())
        self.browser.SetClientHandler(MyJSDialogHandler())
        self.browser.SetClientHandler(MyLoadHandler())

    def OnSetFocus(self, _):
        if not self.browser:
            return
        if WINDOWS:
            WindowUtils.OnSetFocus(self.browser_panel.GetHandle(),
                                   0, 0, 0)
        self.browser.SetFocus(True)

    def OnSize(self, _):
        if not self.browser:
            return
        if WINDOWS:
            WindowUtils.OnSize(self.browser_panel.GetHandle(),
                               0, 0, 0)
        elif LINUX:
            (x, y) = (0, 0)
            (width, height) = self.browser_panel.GetSizeTuple()
            self.browser.SetBounds(x, y, width, height)
        self.browser.NotifyMoveOrResizeStarted()

    def OnClose(self, event):
        print("[wxpython.py] OnClose called")
        if not self.browser:
            # May already be closing, may be called multiple times on Mac
            return

        if MAC:
            # On Mac things work differently, other steps are required
            self.browser.CloseBrowser()
            self.clear_browser_references()
            self.Destroy()
            global g_count_windows
            g_count_windows -= 1
            if g_count_windows == 0:
                cef.Shutdown()
                wx.GetApp().ExitMainLoop()
                # Call _exit otherwise app exits with code 255 (Issue #162).
                # noinspection PyProtectedMember
                os._exit(0)
        else:
            # Calling browser.CloseBrowser() and/or self.Destroy()
            # in OnClose may cause app crash on some paltforms in
            # some use cases, details in Issue #107.
            self.browser.ParentWindowWillClose()
            event.Skip()
            self.clear_browser_references()

    def clear_browser_references(self):
        # Clear browser references that you keep anywhere in your
        # code. All references must be cleared for CEF to shutdown cleanly.
        self.browser = None


"""
class ResourceHandler(object):

    def __init__(self, client_handler, id):
        self.webrequest = None
        self.webrequest_client = WebRequestClient(self)
        self.header_callback = None

    def ProcessRequest(self, request, callback):
        request.SetFlags(cefpython.Request.Flags["AllowCachedCredentials"] |
                         cefpython.Request.Flags["AllowCookies"])
        self.header_callback = callback
        self.webrequest = cefpython.WebRequest.Create(request, self.webrequest_client)
        print(request)
        return True

    def GetResponseHeaders(self, **_):
        print("ReadResponse")
        print (_)

    def ReadResponse(self, **_):
        print("ReadResponse")
        print (_)
"""


class ResourceHandler(object):
    def ProcessRequest(self, request, callback):
        print("ProcessRequest")
        callback.Continue()
        return True

    def GetResponseHeaders(self, response, length, redirect):
        print("GetResponseHeaders")
        print response, response.GetMimeType(), response.GetStatusText(), length, redirect
        return True

    def ReadResponse(self, data, bytes_to_read, bytes_readed, callback):
        print("ReadResponse")
        print data, bytes_to_read, bytes_readed, callback

    def CanGetCookie(self, cookie):
        return True

    def CanSetCookie(self, cookie):
        return True

    def Cancel(self):
        pass


class CefStringVisitor(object):
    def Visit(self, string):
        print(string)


class MyDownloadHandler(object):
    """
    def OnBeforeDownload(self, **_):
        print(_)

    def OnDownloadUpdated(self, **_):
        print(_)
"""


class MyDialogHandler(object):
    pass


class MyJSDialogHandler(object):
    def OnJavascriptDialog(self, **_):
        logging.debug("Enter Function: %s.", _)
        return True

    def OnBeforeUnloadJavascriptDialog(self, **_):
        logging.debug("Enter Function: %s.", _)

    def OnResetJavascriptDialogState(self, **_):
        logging.debug("Enter Function: %s.", _)

    def OnJavascriptDialogClosed(self, **_):
        logging.debug("Enter Function: %s.", _)

    pass


class MyLoadHandler(object):
    def OnBeforeResourceLoad(self, browser, **args):
        '来自RequestHandler的要求'
        # print("\t\tOnBeforeResourceLoad")
        # print(args)
        # cef.PyRequest.GetUrl()
        if args[
            'request'].GetUrl() == 'http://192.168.3.40/p/PowerPointFrame.aspx?embed=1&WOPISrc=http%3A%2F%2F192.168.3.40%3a8081%2fphoenix%2fservice%2fdoc%2fwopi%2ffiles%2F*home*upload*resource_item_global*20171026*a0055507-a54d-4e5d-9114-23caf1135fc4.pptx%2fpptx':
            print args['request'].GetUrl()
            print args['request'].GetHeaderMap()
            print args['request'].GetPostData()
            print args['request'].GetMethod()

    def OnLoadStart(self, browser, frame):
        logging.debug("OnLoadStart ")
        # print(frame.GetSource(CefStringVisitor))
        logging.debug(frame.GetName())
        logging.debug(frame.GetIdentifier())
        logging.debug(frame.IsMain())
        script = """
            tmpFun = window.onload;
            window.onload = function(event){
                tmpFun(event);
                document.getElementById("ReadingToolbarPanel").remove();
                document.getElementById("PptReadingStatusBar.RightDock").style.display='none';
            }
        """
        # logging.debug(browser.ExecuteJavascript('alert(onload)'))
        logging.debug(browser.ExecuteJavascript(script))
        # logging.debug(browser.ExecuteJavascript('alert(onload)'))
        logging.debug("Leave Function.")
        # logging.debug(frame.GetText())
        # logging.debug(frame.GetSource())
        # return
        # strScript = "$('#ReadingToolbarPanel').remove() $('#PptReadingStatusBar\\.RightDock').remove()"
        # strScript = """document.getElementById("#PptReadingStatusBar\\.RightDock").remove()"""
        strScript = """document.getElementById("ReadingToolbarPanel").remove()"""
        print("----------------------------", browser.ExecuteJavascript(strScript))
        strScript = """document.getElementById("PptReadingStatusBar.RightDock").remove()"""
        print("----------------------------", browser.ExecuteJavascript(strScript))

    def OnLoadEnd(self, browser, frame, http_code):
        logging.debug("OnLoadEnd ")
        return
        # strScript = "$('#ReadingToolbarPanel').remove() $('#PptReadingStatusBar\\.RightDock').remove()"
        # strScript = """document.getElementById("#PptReadingStatusBar\\.RightDock").remove()"""
        strScript = """document.getElementById("ReadingToolbarPanel").remove()"""
        print("----------------------------", browser.ExecuteJavascript(strScript))
        strScript = """document.getElementById("PptReadingStatusBar.RightDock").remove()"""
        print("----------------------------", browser.ExecuteJavascript(strScript))

    def OnLoadingStateChange(self, browser, **_):
        """来自LoadHandler的要求"""
        logging.debug(_)

    def OnLoadError(self, browser, **_):
        """来自LoadHandler的要求"""
        logging.debug(_)

    '''
    def OnResourceResponse(self, browser, **args):
        '来自KeyboarHandler的要求'
        print("\t\tOnResourceLoadComplete")
        print(args)
        pass
    '''

    def _OnResourceResponse(self, browser, frame, request, response):
        print(browser)

    def _OnResourceLoadComplete(self, browser, frame, request, response,
                                status, received_content_length):
        print(browser)

    pass


class MyRequestHandler(object):
    def __init__(self):
        self.res = []

    def GetResourceHandler(self, browser, frame, request):
        # logging.debug(request.GetUrl())
        return
        # if not request.GetUrl().startswith('data://'):
        #    return

        res = ResourceHandler()
        self.res.append(res)
        return res

    pass


class MyClientHandler(object):
    def OnGotFocus(self, browser, **_):
        # Temporary fix for focus issues on Linux (Issue #284).
        if LINUX:
            print("[wxpython.py] ClientHandler.OnGotFocus:"
                  " keyboard focus fix (Issue #284)")
            browser.SetFocus(True)


class CefApp(wx.App):
    def __init__(self, redirect):
        self.timer = None
        self.timer_id = 1
        super(CefApp, self).__init__(redirect=redirect)

    def OnInit(self):
        self.create_timer()
        frame = MainFrame()
        self.SetTopWindow(frame)
        frame.Show()
        return True

    def create_timer(self):
        # See also "Making a render loop":
        # http://wiki.wxwidgets.org/Making_a_render_loop
        # Another way would be to use EVT_IDLE in MainFrame.
        self.timer = wx.Timer(self, self.timer_id)
        self.timer.Start(10)  # 10ms timer
        wx.EVT_TIMER(self, self.timer_id, self.on_timer)

    def on_timer(self, _):
        cef.MessageLoopWork()

    def OnExit(self):
        self.timer.Stop()


def check_versions():
    print("[wxpython.py] CEF Python {ver}".format(ver=cef.__version__))
    print("[wxpython.py] Python {ver} {arch}".format(
        ver=platform.python_version(), arch=platform.architecture()[0]))
    print("[wxpython.py] wxPython {ver}".format(ver=wx.version()))
    # CEF Python version requirement
    assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"


def main():
    check_versions()
    sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error
    settings = {}
    if WINDOWS:
        # High DPI support
        settings["auto_zooming"] = "system_dpi"
        # noinspection PyUnresolvedReferences, PyArgumentList
        cef.DpiAware.SetProcessDpiAware()  # Alternative is to embed manifest
    cef.Initialize(settings=settings)
    app = CefApp(False)
    app.MainLoop()
    del app  # Must destroy before calling Shutdown
    if not MAC:
        # On Mac shutdown is called in OnClose
        cef.Shutdown()


if __name__ == '__main__':
    print("------------------    Enter __main__    ------------------")

    print(u"【Current work directory is : 】\t" + os.getcwd())
    print(u"【Current process ID is : 】\t" + str(os.getpid()))
    print("\n")
    main()
    print("\n")
    print("------------------    Leave __main__    ------------------")
